﻿using Decisions.HL7.Message;
using Decisions.HL7.Parser;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;

namespace Decisions.HL7.DataTypes
{
    [DataContract]
    public abstract class AbstractSegment
    {
        [DataMember]
        public string ExcessData { get; set; }

        internal abstract void ConsumeTextSegment(string segmentTextData, HL7ParserOptions options);

        protected static T[] ParseTextAtPositionIntoDataArray<T>(string[] segmentTextParts, int index, HL7ParserOptions options, string dataName) {

            // Check to make sure we have enough data.
            if (index >= segmentTextParts.Length)
            {
                return null;
            }

            List<T> results = new List<T>();

            string[] partsToParse = segmentTextParts[index].Split(options.FieldRepeatSep);
            
            if (partsToParse != null)
            {
                foreach (string eachPart in partsToParse) {
                    results.Add((T)ParseSingleDataElementFromText(eachPart, options, typeof(T), dataName));
                }
            }

            return results.ToArray();
        }

        protected static object ParseTextAtPositionIntoData(string[] segmentTextParts, int index, HL7ParserOptions options, Type type, string dataName)
        {
            if (index >= segmentTextParts.Length)
            {
                return null;
            }

            return ParseSingleDataElementFromText(segmentTextParts[index], options, type, dataName);
        }

        private static object ParseSingleDataElementFromText(string segmentData, HL7ParserOptions options, Type type, string dataName)
        {
            if (typeof(IParseable).IsAssignableFrom(type))
            {
                // If this is an IPArseable we can just 
                // pass it in and let the type parse itself.
                // Instantiate the type
                object dataType = Activator.CreateInstance(type);
                ((IParseable)dataType).Parse(segmentData, options, dataName, options.ComponentSep);
                return dataType;
            }
            else if (ParserRegistry.ParserFor(type))
            {

                var parsedEntity = ParserRegistry.RunParser(type, segmentData);

                return parsedEntity;
            }

            return segmentData;
        }

        internal string GetER7TextForSegmentPart(AbstractDataType segmentData, HL7ParserOptions options)
        {
            if (segmentData == null) {
                return string.Empty;
            }
            return segmentData.GetER7(options);
        }

        internal string GetER7TextForSegmentArrayPart(AbstractDataType[] segmentDataArray, HL7ParserOptions options)
        {
            StringBuilder sb = new StringBuilder();

            if (segmentDataArray != null && segmentDataArray.Length > 0)
            {
                for (int i = 0; i < segmentDataArray.Length; i++)
                {
                    sb.Append(GetER7TextForSegmentPart(segmentDataArray[i], options));

                    if (i != segmentDataArray.Length)
                    {
                        sb.Append(options.FieldRepeatSep);
                    }
                }
            }
            return sb.ToString().TrimEnd(new char[] { options.FieldRepeatSep });
        }

        internal string ConvertStringArray(string[] bits, HL7ParserOptions options) {
            
            StringBuilder sb = new StringBuilder();

            if (bits != null && bits.Length > 0)
            {
                for (int i = 0; i < bits.Length; i++)
                {

                    sb.Append(bits[i]);

                    if (i != bits.Length)
                    {
                        sb.Append(options.FieldRepeatSep);
                    }
                }
            }

            return sb.ToString();
        }

        internal string GetER7TextForSegmentPart(string segmentData)
        {
            return segmentData;
        }

    }
}
